﻿#include "pch.h"
#include "sbhs.h"

//////////////////////////////////////////////////////////////////////////
// 연산자

// 마스크
static const kint _kh_op_mask[KHOP_MAX_VALUE] =
{
	1 << KHOP_NOP,
	1 << KHOP_POS,
	1 << KHOP_NEG,
	1 << KHOP_SIG,
	1 << KHOP_NOT,
	1 << KHOP_INC,
	1 << KHOP_DEC,
	1 << KHOP_MUL,
	1 << KHOP_DIV,
	1 << KHOP_MOD,
	1 << KHOP_ADD,
	1 << KHOP_SUB,
	1 << KHOP_SHL,
	1 << KHOP_SHR,
	1 << KHOP_BLT,
	1 << KHOP_BLE,
	1 << KHOP_BEQ,
	1 << KHOP_BNE,
	1 << KHOP_AND,
	1 << KHOP_XOR,
	1 << KHOP_OR,
	1 << KHOP_STV,
	1 << KHOP_LDV,
	1 << KHOP_NEW,
	1 << KHOP_TOS,
	1 << KHOP_MNM,
};

// 문자열
static const char* _kh_op_name[KHOP_MAX_VALUE] =
{
	"nop",

	"pos",
	"neg",
	"sig",
	"not",
	"inc",
	"dec",

	"mul",
	"div",
	"mod",
	"add",
	"sub",
	"shl",
	"shr",
	"blt",
	"ble",
	"beq",
	"bne",
	"and",
	"xor",
	"or",

	"stv",
	"ldv",

	"new",
	"tos",

	"mnm",
};

// 심볼
static kuint kh_op_symbol[KHOP_MAX_VALUE];

// 초기화
void _k_type_op_init(void)
{
	int i;

	for (i = 0; i < KHOP_MAX_VALUE; i++)
		kh_op_symbol[i] = k_symstt(_kh_op_name[i]);
}

// 문자열
const char* kh_op_to_str(kint op)
{
	k_assert_0(op >= 0 && op <= KHOP_MAX_VALUE);
	return _kh_op_name[op];
}

// 심볼
kuint kh_op_to_sym(kint op)
{
	k_assert_0(op >= 0 && op <= KHOP_MAX_VALUE);
	return kh_op_symbol[op];
}

// 마스크
kint kh_op_to_mask(kint op)
{
	k_assert_0(op >= 0 && op <= KHOP_MAX_VALUE);
	return _kh_op_mask[op];
}


//////////////////////////////////////////////////////////////////////////
// 기본 연산자

// store
int kh_op_supp_stv(kType type, kVar* data, kVar* key, kVar* value)
{
	if (!k_var_is_sym(key))
	{
		k_var_unload(key);
		k_var_unload(value);
	}
	else
	{
		khParamDesc* param = k_type_find_param(type, key->rv.u);

		if (param)
		{
			if (param->prm == KHPRM_PROP)
			{
				struct khParamPropDesc* prop = (struct khParamPropDesc*)param;

				if (!prop->setter)
				{
					// 읽기전용 -> WRITE_DENY
					return 1;
				}
				else
				{
					(*prop->setter)(data->rv.p, prop->offset, value);
					// value값은 setter에서 로드하지 않아도 되도록 언로드 안함
				}
			}
			else if (param->prm == KHPRM_RFN)
			{
				k_halt_impl("k.typeop.stv");
#if 0
				/* 빨간 함수 */
				khParamRedFnDesc rfn;
				rfn.name = desc->data.rfn.name;
				rfn.rfn = hbRedVar_GetRedFn(value);

				if (!rfn.rfn)
					return K_ERROR_INVAL;

				kType_AddParamRedFn(type, &rfn, 1);
				/* kTypeInfo_SetParamRedFn에서 로드 안함 */
				/*hbRedVar_Unload(value);*/
#endif
			}
			else
			{
				// 그외에는 사용 못함
				return 1;
			}
		}
	}

	return 0;
}

// load
int kh_op_supp_ldv(kType type, kVar* data, kVar* key, kVar* value)
{
	if (!k_var_is_sym(key))
	{
		k_var_unload(key);
		k_var_unload(value);
	}
	else
	{
		khParamDesc* param = k_type_find_param(type, key->rv.u);

		if (!param)
			k_var_zero(value);
		else
		{
			if (param->prm == KHPRM_PROP)
			{
				struct khParamPropDesc* prop = (struct khParamPropDesc*)param;

				if (!prop->getter)
				{
					// 쓰기전용 -> READ_DENY
					return 1;
				}
				else
				{
					(*prop->getter)(data->rv.p, prop->offset, value);
					// 반화하는 value에 대해 로드가 필요하면 getter에서 해와야 한다!!!!
				}
			}
			else if (param->prm == KHPRM_FUNC)
			{
				// 함수, 파라미터를 통채로 넣느다
				k_var_set_param(value, param);
			}
			else if (param->prm == KHPRM_RFN)
			{
				// 음...
				k_halt_impl("k.typeop.ldv");
#if 0
				hbRedVar_SetRedFn(value, desc->data.rfn.rfn);
#endif
			}
			else
			{
				// 음!!!
				return 1;
			}
		}
	}

	return 0;
}

// op equal
int kh_op_supp_op_beq(kVar* ops)
{
	k_var_set_bool(&ops[0], ops[0].type == ops[1].type && ops[0].rv.p == ops[1].rv.p);
	return 0;
}

// op not equal
int kh_op_supp_op_bne(kVar* ops)
{
	k_var_set_bool(&ops[0], ops[0].type != ops[1].type || ops[0].rv.p != ops[1].rv.p);
	return 0;
}

// op sig
int kh_op_supp_op_sig(kVar* ops)
{
	k_var_set_bool(&ops[0], (kbool)k_var_is_null(&ops[0]));
	return 0;
}

// op stv
int kh_op_supp_op_stv(kVar* ops)
{
	// 0=들어올때:입력값
	//   나갈때:반환값
	// 1=키
	// 2=값
	return kh_op_supp_stv(ops[0].type, &ops[0], &ops[1], &ops[2]);
}

// op ldv
int kh_op_supp_op_ldv(kVar* ops)
{
	// 0=들어올때:입력값
	//   나갈때:반환값
	// 1=키
	return kh_op_supp_ldv(ops[0].type, &ops[0], &ops[1], &ops[0]);
}

// op new
int kh_op_supp_op_new(kVar* ret, kint arity, kVar* args)
{
	k_var_zero(ret);
	//-- INVAL
	return 1;
}

// op tos
const char* kh_op_supp_op_tos(kVar* var, char* buf, kint size, kint* outlen)
{
	kTypeInfo* info = k_tmnt_look_type(var->type);

	if (outlen)
		*outlen = (kint)k_strlen(info->name);

	return info->name;
}



